//============================================================================
// Name        : PatternGenomAnalyser.cpp
// Author      : Anthea Neums, Jonas Halbach
//			   :
// Description : The Class PatternGenomAnalyser analyses a
//				 genom and matches it to a pattern.
//============================================================================

#include "PatternGenomAnalyser.h"

using namespace std;

namespace algorithm {

PatternGenomAnalyser::PatternGenomAnalyser(FileReader *patternSource,
		FileReader *genomSource, int wordlength, int startpos, int length, int threadNumber) :
		wordlength(wordlength) {

	contentReader = genomSource;
	patternReader = patternSource;

	patternHandler = new PatternHandler(patternReader->getContent(),
			wordlength);

	founds = new list<Found *>();
	lastFound = NULL;
	this->startpos = startpos;
	this->length = length;
	this->threadNumber = threadNumber;

}

PatternGenomAnalyser::~PatternGenomAnalyser() {
	delete patternHandler;
	delete contentReader;
	delete patternReader;
	list<Found *>::iterator listIterator = founds->begin();
	while(listIterator != founds->end())
	{
		delete (*listIterator);
		listIterator++;
	}
	delete founds;
}

/**
 * This Method prints the Vector of the founded matches and adds "Ergebnisliste"
 * at the front and "Ende Ergebnisse" after printing the information about the
 * founds.
 */
void PatternGenomAnalyser::printFounds() {
	cout << "Ergebnisliste:" << endl;
	printMatches();
	cout << "Ende Ergebnisse" << endl;
}

/**
 * This Method prints the Vector of the founded matches and adds a
 * linenumber to each found.
 */
void PatternGenomAnalyser::printMatches() {
	List::iterator it = founds->begin();
	int i = 0;

	while (it != founds->end()) {

		cout << "\t" << i << ") " << flush;
		(*it)->print();
		it++;
		i++;
	}
}

/**
 * This Method finds matching patterns in a genom.
 */
void PatternGenomAnalyser::findSimilarStrings() {
	vector<int> *positions = NULL;
	unsigned int positions_size;
	char *actStringPart = new char[wordlength];
	//Found *actFound = NULL;

	int contentSize = contentReader->getSize();

	//Iterating over the genom-data
	for (int genomPosition = startpos; genomPosition < startpos + length; genomPosition++) {
		//Get the next genom part with the size wordlength
		actStringPart = contentReader->getNext(genomPosition, wordlength);
		if (actStringPart != NULL) {
			//if the string part is not null -> looking in the map if this string
			//also occurs in the pattern
			positions = patternHandler->getPositions(actStringPart);
			if (positions != NULL) {
				//if the string occurs in the pattern-> iterating over the positions,
				//where the string occurs in the pattern
				positions_size = positions->size();
				for (vector<int>::size_type patternPosition = 0; patternPosition < positions_size; patternPosition++) {

					Found *actFound = findSingleMatch(genomPosition, positions->at(patternPosition));
					//founds->push_back(actFound);


					//This part is used to just put Founds of Pattern-Genom-Matches if
					//the bounds of the found are outside of old founds
					if (lastFound != NULL) {
						if (!lastFound->contains(actFound)) {
							founds->push_back(actFound);
							lastFound = actFound;
						}

					} else {
						lastFound = actFound;
						founds->push_back(actFound);
					}
				}

			}
		}

	}

}



/**
 * This Method prooves if the pattern and the genom are matching over the specified bounds.
 * @param genomPosition 	: one Position of the genom, where the pattern and the genom match
 * @param patternPosition 	: one Position in the pattern, where genom and Pattern match.
 * @param n 				: is the minimal length of matching chars in the genom and pattern.
 * @return					: An pointer to a Found-object which stores the information about the
 * 								founded match.
 */
Found *PatternGenomAnalyser::findSingleMatch(int genomPosition,	int patternPosition) {
	//matchCount has got the size n because thats the minimun pattern-size stored in the map, which connects the patterns with positions in the patternstring.
	int matchCount = wordlength;

	//Getting the content of the genom and the actual char which has to be compared with the char in the pattern.

	char *content = contentReader->getContent();

	//Getting the content of the pattern and the actual char which has to be compared with the char in the genom.
	char *pattern = patternReader->getContent();

	// Getting the size of the content- and pattern String to know when to stop.
	int contentSize = contentReader->getSize();
	int patternSize = patternReader->getSize();

	//Proving if the indexes are in the bounds of the strings
	if (patternPosition + matchCount < patternSize
			&& genomPosition + matchCount < contentSize) {

		char actGenomChar = content[genomPosition + matchCount];
		char actPatternChar = pattern[patternPosition + matchCount];

		// Compare both chars at the same position. If they are the same the matchCount-variable will be raised by 1.
		while (actPatternChar == actGenomChar
				&& ((patternPosition + matchCount) < patternSize - 1)
				&& ((genomPosition + matchCount) < contentSize - 1)) {
			//raising matchCound because the old chars in the pattern and genom are the same.
			matchCount++;

			// updating the actual chars to compare.
			actPatternChar = pattern[patternPosition + matchCount];
			actGenomChar = content[genomPosition + matchCount];

		}

		//Proving is loop is left just because index is out ouf bounds and if the chars are just the same
		if (actPatternChar == actGenomChar
				&& (((patternPosition + matchCount) >= patternSize - 1)
						|| ((genomPosition + matchCount) >= contentSize - 1))) {
			matchCount++;
		}
	}

	char *matchingString = contentReader->getNext(genomPosition, matchCount);

	Found *found = new Found(genomPosition, patternPosition, matchCount,
			matchingString);

	return found;
}

list<Found *> *PatternGenomAnalyser::getFounds() {
	return founds;
}

int PatternGenomAnalyser::getThreadNumber()
{
	return threadNumber;
}

} /* namespace algorithm */
